<template>
  <div class="qr-generator">
    <h1 class="title">码生成器</h1>
    <div class="description">生成并下载文本或URL的二维码/条形码，并自定义样式。</div>

    <div class="code-type-selector">
      <a-radio-group v-model:value="codeType" button-style="solid">
        <a-radio-button value="qrcode">二维码</a-radio-button>
        <a-radio-button value="barcode">条形码</a-radio-button>
      </a-radio-group>
    </div>

    <div class="generator-container">
      <!-- 输入区域 -->
      <div class="input-section">
        <div class="input-group">
          <label>文本:</label>
          <a-textarea v-model:value="text" :placeholder="codeType === 'qrcode' ? '请输入文本或URL' : '请输入数字或字母'" :rows="4" @focus="handleTextareaFocus" @blur="handleTextareaBlur" />
          <div v-if="codeType === 'barcode'" class="barcode-hint">注意：条形码仅支持数字和字母，不同格式有不同限制</div>
        </div>

        <div class="color-group">
          <div class="input-group">
            <label>前景色:</label>
            <div class="color-input-wrapper">
              <a-input v-model:value="foreground" placeholder="#000000" @change="validateColor" />
              <input type="color" :value="foreground" @input="(e) => (foreground = e.target.value)" class="color-picker" />
            </div>
          </div>

          <div class="input-group">
            <label>背景色:</label>
            <div class="color-input-wrapper">
              <a-input v-model:value="background" placeholder="#ffffff" @change="validateColor" />
              <input type="color" :value="background" @input="(e) => (background = e.target.value)" class="color-picker" />
            </div>
          </div>
        </div>

        <!-- 二维码特有设置 -->
        <div v-if="codeType === 'qrcode'" class="input-group">
          <label>纠错级别:</label>
          <div class="error-level-description">选择二维码的容错能力，级别越高越能容忍遮挡和损坏</div>
          <a-radio-group v-model:value="errorLevel" button-style="solid" class="error-level-group">
            <a-radio-button value="L">低 (7%)</a-radio-button>
            <a-radio-button value="M">中 (15%)</a-radio-button>
            <a-radio-button value="Q">较高 (25%)</a-radio-button>
            <a-radio-button value="H">高 (30%)</a-radio-button>
          </a-radio-group>
          <div class="format-description">
            {{ getErrorLevelDescription(errorLevel) }}
          </div>
        </div>

        <!-- 条形码特有设置 -->
        <div v-if="codeType === 'barcode'" class="input-group">
          <label>条形码格式:</label>
          <a-radio-group v-model:value="barcodeFormat" button-style="solid" class="barcode-format-group">
            <a-radio-button value="CODE128">CODE128</a-radio-button>
            <a-radio-button value="EAN13">EAN-13</a-radio-button>
            <a-radio-button value="EAN8">EAN-8</a-radio-button>
            <a-radio-button value="UPC">UPC</a-radio-button>
            <a-radio-button value="CODE39">CODE39</a-radio-button>
            <a-radio-button value="ITF14">ITF-14</a-radio-button>
          </a-radio-group>
          <div class="format-description">
            {{ getFormatDescription(barcodeFormat) }}
          </div>
        </div>

        <div v-if="codeType === 'barcode'" class="input-group">
          <label>宽度:</label>
          <a-slider v-model:value="barcodeWidth" :min="1" :max="4" :step="0.5" />
        </div>

        <div v-if="codeType === 'barcode'" class="input-group">
          <label>高度:</label>
          <a-slider v-model:value="barcodeHeight" :min="40" :max="120" :step="10" />
        </div>

        <div v-if="codeType === 'barcode'" class="input-group">
          <a-checkbox v-model:checked="showBarcodeText">显示文本</a-checkbox>
        </div>
      </div>

      <!-- 预览区域 -->
      <div class="preview-section">
        <div class="qr-wrapper" ref="codeWrapper">
          <!-- 二维码预览 -->
          <qrcode-vue v-if="codeType === 'qrcode' && text" :value="text" :size="280" :level="errorLevel" :foreground="foreground" :background="background" render-as="svg" />

          <!-- 条形码预览 -->
          <svg v-else-if="codeType === 'barcode' && text" ref="barcodeElement"></svg>

          <!-- 占位符 -->
          <div v-else class="placeholder">请输入文本生成{{ codeType === 'qrcode' ? '二维码' : '条形码' }}</div>
        </div>

        <div class="download-buttons">
          <a-button-group>
            <a-button type="primary" :disabled="!text" @click="downloadCode('svg')"> 下载 SVG </a-button>
            <a-button type="primary" :disabled="!text" @click="downloadCode('png')"> 下载 PNG </a-button>
          </a-button-group>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, watch, nextTick } from 'vue'
import QrcodeVue from 'qrcode.vue'
import JsBarcode from 'jsbarcode'
import { message } from 'ant-design-vue'
import { onMounted, onUnmounted } from 'vue'

// 响应式状态
const text = ref('')
const foreground = ref('#000000')
const background = ref('#ffffff')
const errorLevel = ref('M')
const codeWrapper = ref(null)
const isTextareaFocused = ref(false)
const codeType = ref('qrcode') // 'qrcode' 或 'barcode'
const barcodeElement = ref(null)

// 条形码特有设置
const barcodeFormat = ref('CODE128')
const barcodeWidth = ref(2)
const barcodeHeight = ref(80)
const showBarcodeText = ref(true)

// 处理键盘事件
const handleKeydown = (e) => {
  if (isTextareaFocused.value) {
    // 当文本框处于焦点状态时，阻止事件冒泡
    e.stopPropagation()
  }
}

// 文本框焦点处理
const handleTextareaFocus = () => {
  isTextareaFocused.value = true
}

const handleTextareaBlur = () => {
  isTextareaFocused.value = false
}

// 组件挂载时添加事件监听
onMounted(() => {
  document.addEventListener('keydown', handleKeydown, true)
})

// 组件卸载时移除事件监听
onUnmounted(() => {
  document.removeEventListener('keydown', handleKeydown, true)
})

// 验证颜色格式
const validateColor = (e) => {
  const colorRegex = /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/
  const value = e.target.value

  if (!colorRegex.test(value)) {
    message.error('请输入有效的十六进制颜色代码')
    return false
  }
  return true
}

// 生成条形码
const generateBarcode = () => {
  if (!text.value || !barcodeElement.value) return

  try {
    // 清空之前的内容
    barcodeElement.value.innerHTML = ''

    // 根据不同格式验证输入
    let isValid = true
    let errorMsg = ''

    if (barcodeFormat.value === 'EAN13' && !/^\d{13}$/.test(text.value)) {
      isValid = false
      errorMsg = 'EAN-13格式需要13位数字'
    } else if (barcodeFormat.value === 'EAN8' && !/^\d{8}$/.test(text.value)) {
      isValid = false
      errorMsg = 'EAN-8格式需要8位数字'
    } else if (barcodeFormat.value === 'UPC' && !/^\d{12}$/.test(text.value)) {
      isValid = false
      errorMsg = 'UPC格式需要12位数字'
    } else if (barcodeFormat.value === 'ITF14' && !/^\d{14}$/.test(text.value)) {
      isValid = false
      errorMsg = 'ITF-14格式需要14位数字'
    }

    if (!isValid) {
      message.error(errorMsg)
      return
    }

    // 生成条形码
    JsBarcode(barcodeElement.value, text.value, {
      format: barcodeFormat.value,
      lineColor: foreground.value,
      background: background.value,
      width: barcodeWidth.value,
      height: barcodeHeight.value,
      displayValue: showBarcodeText.value,
      fontSize: 16,
      margin: 10
    })
  } catch (error) {
    message.error('生成条形码失败: ' + error.message)
  }
}

// 监听条形码相关参数变化，重新生成条形码
watch([text, foreground, background, barcodeFormat, barcodeWidth, barcodeHeight, showBarcodeText, codeType], () => {
  if (codeType.value === 'barcode') {
    nextTick(() => {
      generateBarcode()
    })
  }
})

// 下载码
const downloadCode = (format = 'svg') => {
  if (!text.value) return

  // 获取要下载的元素
  let element
  if (codeType.value === 'qrcode') {
    element = codeWrapper.value.querySelector('svg')
  } else {
    element = barcodeElement.value
  }

  if (!element) {
    message.error('未找到可下载的元素')
    return
  }

  if (format === 'svg') {
    const serializer = new XMLSerializer()
    const source = serializer.serializeToString(element)
    const url = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(source)}`
    const link = document.createElement('a')
    link.href = url
    link.download = codeType.value === 'qrcode' ? 'qrcode.svg' : 'barcode.svg'
    document.body.appendChild(link)
    link.click()
    document.body.removeChild(link)
  } else {
    // 创建 Canvas 并绘制 SVG
    const canvas = document.createElement('canvas')
    const ctx = canvas.getContext('2d')
    const svgData = new XMLSerializer().serializeToString(element)
    const img = new Image()

    // 设置 canvas 尺寸
    if (codeType.value === 'qrcode') {
      canvas.width = 560 // 2倍大小以获得更清晰的图像
      canvas.height = 560
    } else {
      // 条形码尺寸可能不是正方形
      const rect = element.getBoundingClientRect()
      canvas.width = rect.width * 2
      canvas.height = rect.height * 2
    }

    img.onload = () => {
      ctx.fillStyle = background.value
      ctx.fillRect(0, 0, canvas.width, canvas.height)
      ctx.drawImage(img, 0, 0, canvas.width, canvas.height)

      // 转换为 PNG 并下载
      try {
        const url = canvas.toDataURL('image/png')
        const link = document.createElement('a')
        link.href = url
        link.download = codeType.value === 'qrcode' ? 'qrcode.png' : 'barcode.png'
        document.body.appendChild(link)
        link.click()
        document.body.removeChild(link)
      } catch (err) {
        message.error('生成PNG图片失败，请重试')
      }
    }

    img.onerror = () => {
      message.error('生成PNG图片失败，请重试')
    }

    // 将 SVG 转换为 base64
    const svgBlob = new Blob([svgData], { type: 'image/svg+xml;charset=utf-8' })
    const reader = new FileReader()

    reader.onload = (e) => {
      img.src = e.target.result
    }

    reader.readAsDataURL(svgBlob)
  }
}

// 获取条形码格式描述
const getFormatDescription = (format) => {
  const descriptions = {
    CODE128: '通用字母数字，支持所有ASCII字符',
    EAN13: '13位数字，常用于零售商品',
    EAN8: '8位数字，用于小型包装商品',
    UPC: '12位数字，北美通用商品代码',
    CODE39: '字母数字和特殊字符，工业应用广泛',
    ITF14: '14位数字，用于物流包装'
  }
  return descriptions[format] || ''
}

// 获取二维码错误级别描述
const getErrorLevelDescription = (level) => {
  const descriptions = {
    L: '适合清晰打印环境，容错率低',
    M: '适合一般场景，平衡容错率和数据容量',
    Q: '适合户外使用，能抵抗部分污损',
    H: '适合添加Logo或装饰，容错率最高'
  }
  return descriptions[level] || ''
}
</script>

<style scoped>
.qr-generator {
  max-width: 1000px;
  margin: 0 auto;
  padding: 20px;
}

.title {
  text-align: center;
  margin-bottom: 10px;
  color: #333;
}

.description {
  text-align: center;
  color: #666;
  margin-bottom: 20px;
}

.code-type-selector {
  display: flex;
  justify-content: center;
  margin-bottom: 30px;
}

.generator-container {
  display: flex;
  gap: 40px;
  background: #fff;
  padding: 30px;
  border-radius: 8px;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
}

.input-section {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.input-group {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.input-group label {
  font-weight: 500;
  color: #333;
}

.color-group {
  display: flex;
  gap: 20px;
}

.color-group .input-group {
  flex: 1;
}

.preview-section {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 20px;
}

.qr-wrapper {
  width: 280px;
  height: 280px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #f5f5f5;
  border-radius: 8px;
  padding: 20px;
  overflow: hidden;
}

.placeholder {
  color: #999;
  text-align: center;
}

.barcode-hint {
  font-size: 12px;
  color: #ff4d4f;
  margin-top: 4px;
}

@media (max-width: 768px) {
  .generator-container {
    flex-direction: column;
  }

  .qr-wrapper {
    width: 100%;
    height: auto;
    aspect-ratio: 1;
  }
}

.color-input-wrapper {
  display: flex;
  gap: 8px;
  align-items: center;
}

.color-input-wrapper :deep(.ant-input) {
  flex: 1;
}

.color-input-wrapper :deep(.ant-color-picker-trigger) {
  width: 32px;
  height: 32px;
  border: 1px solid #d9d9d9;
  border-radius: 4px;
}

.color-picker {
  width: 32px;
  height: 32px;
  padding: 0;
  border: 1px solid #d9d9d9;
  border-radius: 4px;
  cursor: pointer;
}

.color-picker::-webkit-color-swatch-wrapper {
  padding: 0;
}

.color-picker::-webkit-color-swatch {
  border: none;
  border-radius: 2px;
}

.download-buttons {
  display: flex;
  gap: 10px;
}

.error-level-description {
  font-size: 12px;
  color: #666;
  margin-bottom: 4px;
}

.barcode-format-group {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 8px;
}

.barcode-format-group :deep(.ant-radio-button-wrapper) {
  margin-right: 0;
  margin-bottom: 8px;
}

.format-description {
  font-size: 12px;
  color: #666;
  margin-top: 4px;
}

@media (max-width: 768px) {
  .barcode-format-group {
    flex-direction: column;
  }

  .barcode-format-group :deep(.ant-radio-button-wrapper) {
    width: 100%;
    text-align: center;
  }
}

.error-level-group {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 8px;
}

.error-level-group :deep(.ant-radio-button-wrapper) {
  margin-right: 0;
  margin-bottom: 8px;
}

@media (max-width: 768px) {
  .error-level-group {
    flex-direction: column;
  }

  .error-level-group :deep(.ant-radio-button-wrapper) {
    width: 100%;
    text-align: center;
  }
}
</style>
